﻿using ClosedXML.Excel;
using ClosedXML.Excel.Exceptions;
using DocumentFormat.OpenXml.Packaging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Documents;
using System.Windows.Media;

namespace Simple_search.Data
{
    public class BlockResult : IDisposable
    {
        public IBook Book { get; }
        public int StartBlockId { get; }
        public int EndBlockId { get; }
        public Dictionary<SearchUnit, List<SearchResult>> ResultCombination { get; } = new();

        public BlockResult(IBook book, List<BlockCombination> orderdBlockCombinations, int endBlockId)
        {
            Book = book;
            StartBlockId = orderdBlockCombinations[0].StartBlockId;
            EndBlockId = endBlockId;

            foreach (BlockCombination blockCombination in orderdBlockCombinations)
            {
                if (ResultCombination.ContainsKey(blockCombination.Unit))
                {
                    ResultCombination[blockCombination.Unit].Add(blockCombination.Result);
                }
                else
                {
                    ResultCombination.Add(blockCombination.Unit, new List<SearchResult>() { blockCombination.Result });
                }
            }
        }

        public BlockResult(IBook book, BlockCombination blockCombination)
        {
            Book = book;
            StartBlockId = blockCombination.StartBlockId;
            EndBlockId= blockCombination.EndBlockId;
            ResultCombination.Add(blockCombination.Unit, new() { blockCombination.Result });
        }

        public void PrintToExcel(IXLWorksheet sheet, int rowIndex)
        {
            string blockContent = Book.GetBlockContent(StartBlockId, EndBlockId);
            sheet.Cell(rowIndex, 1).Value = Book.Name;
            sheet.Cell(rowIndex, 3).Value = ResultCombination.Count;
            IXLRichText unitCell = sheet.Cell(rowIndex, 2).CreateRichText();
            IXLRichText contentCell = sheet.Cell(rowIndex, 4).CreateRichText();
            contentCell.AddText(blockContent);
            foreach (SearchUnit searchUnit in ResultCombination.Keys)
            {
                string name = searchUnit.Name;
                XLColor color = GetColor(searchUnit);
                unitCell.AddText(name).SetFontColor(color);
                unitCell.AddText(",");
                foreach (SearchResult searchResult in ResultCombination[searchUnit])
                {
                    int offset = GetOffset(searchResult);
                    contentCell.Substring(offset, searchResult.Length).SetFontColor(color);
                }
            }
        }

        public void PrintToExcelNoRichtext(IXLWorksheet sheet, int rowIndex)
        {
            string blockContent = Book.GetBlockContent(StartBlockId, EndBlockId);
            sheet.Cell(rowIndex, 1).Value = Book.Name;
            sheet.Cell(rowIndex, 3).Value = ResultCombination.Count;
            sheet.Cell(rowIndex, 4).Value = blockContent;
            string terms = string.Empty;
            foreach (SearchUnit searchUnit in ResultCombination.Keys)
            {
                terms += searchUnit.Name + ",";
            }
            sheet.Cell(rowIndex, 2).Value = terms;

        }

        private XLColor GetColor(SearchUnit searchUnit)
        {
            Color color = searchUnit.MarkColor;
            return XLColor.FromArgb(color.A, color.R, color.G, color.B);
        }

        private int GetOffset(SearchResult searchResult)
        {
            return searchResult.Start - StartBlockId * Book.BlockSize;
        }

        public void Dispose()
        {
            ResultCombination.Clear();
        }
    }

    public struct BlockCombination
    {
        public int StartBlockId;
        public int EndBlockId;
        public SearchResult Result;
        public SearchUnit Unit;
        public bool IsEmpty;
        public BlockCombination(SearchUnit unit, SearchResult result)
        {
            StartBlockId = result.StartBlockId;
            EndBlockId = result.EndBlockId;
            Unit = unit;
            Result = result;
            IsEmpty = false;
        }

        public static BlockCombination Empty {
            get
            {
                return new BlockCombination() { IsEmpty = true };
            } }
    }
}
